Skip to content

Conversation

@muntaxir4
Copy link
Contributor

@muntaxir4 muntaxir4 commented Apr 8, 2025

Depends on feat: Realtime Scalable chat among brands and creators (#56)

Initial PR: WebRTC Video Calling with WebSocket Signaling

📝 Description

This PR lays the groundwork for real-time video calling using WebRTC, integrated with a WebSocket-based signaling server for peer-to-peer connection negotiation. The signaling flow handles offer/answer exchange and ICE candidate distribution between clients. This marks the initial step in adding robust, scalable, and low-latency video communication support to the platform.


🔧 Changes Made

Backend (FastAPI):

  • WebSocket endpoint: route for offer, answer, and ICE candidate exchange.
  • Connection manager: Maintains in-memory peer sessions and mapping via user IDs or room IDs.
  • Broadcast logic: Routes signals from caller to callee and vice versa via WebSocket.

Frontend:

  • Basic WebRTC logic using RTCPeerConnection.
  • Media capture setup using navigator.mediaDevices.getUserMedia.
  • Socket signaling client:
  • Connects to backend WebSocket.
  • Sends offers/answers and ICE candidates.
  • Handles remote stream and peer connection.

📌 Next Steps (Same PR)

  • Add STUN/TURN server support for better NAT traversal.
  • Improve room management and signaling error handling.
  • UI/UX enhancements for call controls (mute, end call, etc.).
  • Add user presence indication and busy signal logic.

Summary by CodeRabbit

  • New Features

    • Introduced real-time chat functionality with WebSocket support, including chat lists, message history, read receipts, and online status tracking.
    • Added video calling capabilities within chat, including call initiation, signaling, and media stream management.
    • Implemented a searchable chat interface with chat creation, message sending, and message status indicators.
    • Added Redux-based state management for chats and messages in the frontend.
    • Integrated Redis for real-time message delivery and online presence tracking.
    • Provided Docker Compose setup for Redis service.
  • Improvements

    • Unified timestamp handling to timezone-aware format across all backend models.
    • Enhanced user tracking with online status and last seen information.
  • Bug Fixes

    • Improved CORS configuration to enable frontend-backend integration.
  • Documentation

    • Updated README with Redis setup instructions.
  • Chores

    • Updated frontend dependencies to include state management and UI libraries.
    • Extended .gitignore to cover environment files.

@ishaanxgupta
Copy link
Contributor

@muntaxir4 Please add screenshots

@muntaxir4
Copy link
Contributor Author

@muntaxir4 Please add screenshots

Hey this is still in Draft. I will push the final changes soon.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 7, 2025

Walkthrough

This update introduces a comprehensive real-time chat and video calling system to the application. It adds backend chat models, WebSocket and REST API routes, Redis-based pub/sub infrastructure, and frontend React components for chat UI, video calling, and Redux-based state management. Supporting utilities, configuration, and documentation are also updated.

Changes

File(s) / Path(s) Change Summary
Backend/app/db/db.py, Backend/app/db/seed.py Added async DB session generator (get_db) and seeding function (seed_db).
Backend/app/main.py Added CORS, chat table creation, DB seeding, and chat API route inclusion.
Backend/app/models/chat.py Introduced ChatList, ChatMessage models, and MessageStatus enum for chat.
Backend/app/models/models.py Unified timestamps to timezone-aware, added online status fields, clarified payment relationships.
Backend/app/routes/chat.py Implemented chat WebSocket and REST endpoints for messaging and signaling.
Backend/app/services/chat_pubsub.py Added Redis pub/sub listener for real-time WebSocket message delivery.
Backend/app/services/chat_services.py Implemented ChatService class for chat, message, and signaling logic.
Backend/app/services/redis_client.py Added async Redis client and dependency provider.
Backend/docker-compose.yml Introduced Redis service for pub/sub messaging.
Frontend/.gitignore Now ignores .env* files.
Frontend/package.json Added Radix UI, Redux Toolkit, React-Redux, and Axios dependencies.
Frontend/src/App.tsx Added /creator/messages route for new chat UI.
Frontend/src/components/chat/* Added new components: Chat, ChatList, ChatItem, ChatSearch, CreateNewChat, MessageInput, MessageItem, MessagesList, MessagesView, SelectedUserCard for chat UI.
Frontend/src/components/ui/dialog.tsx Added Radix-based Dialog UI components.
Frontend/src/components/video-calling/* Added CallStarter and VideoCallUI components for video calling.
Frontend/src/lib/useChat.tsx, Frontend/src/lib/useVideocall.tsx Implemented chat and video call context/providers and hooks.
Frontend/src/lib/utils.ts Added API_URL export and syntax improvements.
Frontend/src/main.tsx Integrated Redux store provider.
Frontend/src/pages/Brand/Dashboard.tsx, Frontend/src/pages/Messages.tsx Replaced old messaging UI with new Chat component.
Frontend/src/redux/chatSlice.ts, Frontend/src/redux/store.ts Added Redux chat slice and store configuration.
Frontend/src/types/chat.ts Added types for chat events and messages.
README.md Updated installation instructions to include Redis setup.

Sequence Diagram(s)

sequenceDiagram
    participant FE as Frontend (React)
    participant WS as WebSocket
    participant BE as Backend (FastAPI)
    participant Redis as Redis Pub/Sub
    participant DB as Database

    FE->>WS: Connect (user_id)
    WS->>BE: WebSocket upgrade
    BE->>Redis: Subscribe to to_user:{user_id}
    FE->>BE: SEND_MESSAGE event (receiver_id, message)
    BE->>DB: Store message in ChatMessage
    BE->>Redis: Publish message to to_user:{receiver_id}
    Redis-->>BE: Pub/Sub message
    BE->>WS: Send new message event
    FE->>WS: Receive new message event
    FE->>BE: Mark message as read (REST)
    BE->>DB: Update message status
    BE->>Redis: Publish read receipt to to_user:{sender_id}
    FE->>WS: Receive read receipt event
Loading
sequenceDiagram
    participant FE as Frontend (React)
    participant WS as WebSocket
    participant BE as Backend (FastAPI)
    participant Redis as Redis Pub/Sub

    FE->>WS: VIDEO_OFFER event (target_user_id, offer)
    BE->>Redis: Publish offer to to_user:{target_user_id}
    Redis-->>BE: Pub/Sub offer
    BE->>WS: Send VIDEO_OFFER to target
    FE->>WS: Receive VIDEO_OFFER, respond with VIDEO_ANSWER
    BE->>Redis: Publish answer to to_user:{sender_id}
    Redis-->>BE: Pub/Sub answer
    BE->>WS: Send VIDEO_ANSWER to initiator
Loading

Possibly related PRs

  • AOSSIE-Org/InPactAI#56: Adds the same async DB session generator and seeding function as in this PR, indicating direct code-level overlap in backend database initialization.

Suggested labels

enhancement, frontend, backend

Poem

🐇
In tunnels deep, we built a chat,
With messages quick—imagine that!
Now bunnies can call, and faces appear,
Thanks to Redis and WebSocket cheer.
With Redux and Radix, the frontend’s a breeze,
So hop in and message—just type with ease!
🥕💬

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@muntaxir4 muntaxir4 marked this pull request as ready for review June 30, 2025 13:07
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 47

🔭 Outside diff range comments (1)
Frontend/src/pages/Messages.tsx (1)

236-398: Remove the hidden legacy messaging UI code.

The old messaging interface is being hidden via CSS class hidden but the entire codebase remains. This creates technical debt and potential confusion.

Consider removing the legacy messaging code entirely rather than hiding it:

-      {/* Old Code */}
-      <main className="flex-1 hidden">
-        {/* ... entire old messaging UI ... */}
-      </main>

If you need to keep it for reference during development, consider using feature flags or moving it to a separate branch rather than shipping hidden code to production.

🧹 Nitpick comments (18)
Backend/app/services/redis_client.py (1)

3-3: Flag production readiness concern for Redis configuration

While the hardcoded Redis connection parameters are acceptable for development (as noted in previous feedback), consider implementing environment variable configuration for production deployment to support different Redis instances and credentials.

Future production enhancement could include:

-redis_client = redis.Redis(host="localhost", port=6379, decode_responses=True)
+redis_client = redis.Redis(
+    host=os.getenv("REDIS_HOST", "localhost"),
+    port=int(os.getenv("REDIS_PORT", "6379")),
+    password=os.getenv("REDIS_PASSWORD"),
+    decode_responses=True
+)
Frontend/src/main.tsx (1)

9-9: Clean up commented code.

Based on the retrieved learning that StrictMode should be disabled when using WebSockets, consider removing the commented lines entirely or using conditional logic for development vs production environments.

-  // <StrictMode>
   <Provider store={store}>
     <App />
   </Provider>
-  // </StrictMode>,

Also applies to: 13-13

Backend/docker-compose.yml (1)

1-14: Consider adding Redis security configuration for production readiness.

While the current configuration works for development, consider adding authentication and other security measures when moving to production:

 services:
   redis:
-    image: redis:latest
+    image: redis:7-alpine
     container_name: redis
     ports:
       - "6379:6379"
     volumes:
       - redis_data:/data
     restart: unless-stopped
-    command: redis-server --appendonly yes
+    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-devpassword}
+    environment:
+      - REDIS_PASSWORD=${REDIS_PASSWORD:-devpassword}
Frontend/src/components/chat/chat.tsx (1)

8-42: Enhance UX with loading states and disconnect functionality.

The component lacks loading states during connection and provides no way to disconnect once connected.

Consider adding:

  1. Loading state while connecting
  2. Disconnect functionality
  3. Error handling for connection failures
  4. Better user feedback
export default function Chat() {
  const [inputUserId, setInputUserId] = useState<string | null>(null);
  const [userId, setUserId] = useState<string | null>(null);
+ const [isConnecting, setIsConnecting] = useState(false);
+ const [connectionError, setConnectionError] = useState<string | null>(null);

+ const handleConnect = async () => {
+   if (!inputUserId?.trim()) return;
+   setIsConnecting(true);
+   setConnectionError(null);
+   try {
+     // Add connection logic here
+     setUserId(inputUserId.trim());
+   } catch (error) {
+     setConnectionError('Failed to connect');
+   } finally {
+     setIsConnecting(false);
+   }
+ };

+ const handleDisconnect = () => {
+   setUserId(null);
+   setInputUserId(null);
+ };
Frontend/src/components/chat/message-input.tsx (2)

20-30: Add error handling and loading state for message sending.

The component doesn't handle potential errors from the sendMessage operation or provide user feedback during sending.

Consider adding error handling and loading state:

+  const [isSending, setIsSending] = useState(false);
+  const [sendError, setSendError] = useState<string | null>(null);

-  const handleSendMessage = () => {
+  const handleSendMessage = async () => {
    if (message.trim() === "") return;
    if (!receiverId) {
      console.warn("No receiver selected");
      return;
    }
+    
+    setIsSending(true);
+    setSendError(null);
+    
+    try {
-      sendMessage(receiverId, message);
+      await sendMessage(receiverId, message);
      setMessage("");
      // ... scroll logic ...
+    } catch (error) {
+      setSendError("Failed to send message");
+      console.error("Send message error:", error);
+    } finally {
+      setIsSending(false);
+    }
  };

47-52: Add accessibility improvements and visual feedback.

The send button lacks proper accessibility attributes and doesn't show loading state.

Enhance the button with accessibility and loading state:

        <Button
          className="bg-purple-700 hover:bg-purple-800 text-white"
          onClick={handleSendMessage}
+          disabled={isSending || !message.trim() || !receiverId}
+          aria-label="Send message"
        >
-          <Send className="h-4 w-4" />
+          {isSending ? (
+            <div className="animate-spin h-4 w-4 border-2 border-white border-t-transparent rounded-full" />
+          ) : (
+            <Send className="h-4 w-4" />
+          )}
        </Button>
Backend/app/db/seed.py (2)

1-1: Remove unused imports.

The datetime and timezone imports are not used anywhere in the code.

-from datetime import datetime, timezone

35-50: Remove unnecessary else clause after continue.

The else clause is unnecessary after a continue statement and increases indentation depth.

             if existing_user:
                 continue
-            else:
-                # Create new user
-                user = User(
-                    id=user_data["id"],
-                    username=user_data["username"],
-                    email=user_data["email"],
-                    password_hash=user_data[
-                        "password"
-                    ],  # Using plain password directly
-                    role=user_data["role"],
-                    bio=user_data["bio"],
-                )
-                session.add(user)
-                print(f"Created user: {user_data['email']}")
+            
+            # Create new user
+            user = User(
+                id=user_data["id"],
+                username=user_data["username"],
+                email=user_data["email"],
+                password_hash=user_data["password"],
+                role=user_data["role"],
+                bio=user_data["bio"],
+            )
+            session.add(user)
+            print(f"Created user: {user_data['email']}")
Frontend/src/components/chat/chat-list.tsx (1)

20-25: Add dependency array to prevent unnecessary re-fetches.

The fetchChatList call should include fetchChatList in the dependency array to follow React's exhaustive-deps rule, even though it's likely stable.

   useEffect(() => {
     setLoading(true);
     fetchChatList().finally(() => {
       setLoading(false);
     });
-  }, []);
+  }, [fetchChatList]);
Frontend/src/components/video-calling/call-starter.tsx (1)

19-20: Remove commented out code.

The commented out sendVideoSignal call should be removed as it's not being used and clutters the codebase.

   const handleStartCall = () => {
     setIsOpen(true);
-    // Initiate the call by sending an offer signal
-    // sendVideoSignal(targetUserId, "VIDEO_OFFER", {}); // Empty payload for offer initiation
     startCall(targetUserId);
   };
Frontend/src/components/chat/message-item.tsx (1)

8-53: Consider memoizing the component for performance.

Since this component renders frequently in chat lists, consider using React.memo to prevent unnecessary re-renders when props haven't changed.

-export default function MessageItem({ message }: { message: Message }) {
+export default React.memo(function MessageItem({ message }: { message: Message }) {
   return (
     // ... component content
   );
-}
+});
Frontend/src/components/chat/chat-item.tsx (1)

27-31: Optimize Redux selector to prevent unnecessary re-renders.

The inline selector function is recreated on every render. Consider using useCallback or useMemo to memoize the selector logic.

+  const lastMessage = useSelector((state: RootState) => {
+    if (!chat.messageIds.length) return null;
+    const lastMessageId = chat.messageIds[chat.messageIds.length - 1];
+    return state.chat.messages[lastMessageId]?.message || null;
+  });
-  const lastMessage = useSelector((state: RootState) =>
-    chat.messageIds.length
-      ? state.chat.messages[chat.messageIds[chat.messageIds.length - 1]].message
-      : null
-  );
Frontend/src/types/chat.ts (1)

1-4: Add JSDoc documentation for interface clarity.

The MessagesReadResponse interface should have documentation explaining its purpose and usage context.

+/**
+ * Represents a messages read event payload indicating all messages in a chat have been marked as read
+ */
export interface MessagesReadResponse {
  chatListId: string;
  eventType: "MESSAGES_READ";
}
Frontend/src/lib/useVideocall.tsx (2)

143-158: Complete the accept/reject call functionality.

The commented-out accept/reject call logic should either be implemented or removed to avoid confusion.

These functions appear to be placeholders for call acceptance/rejection logic. Would you like me to help implement these functions or should they be removed if not needed for the current implementation?


28-28: Remove debug logging in production code.

The console.log statement for debugging should be removed or replaced with proper logging mechanism for production.

-      console.log("Sending WebSocket message:", message); // Log the stringified message
+      // Consider using a proper logging service instead of console.log
Backend/app/routes/chat.py (1)

106-107: Enhance error messages for better debugging

The validation error messages could be more descriptive to help with debugging.

     if not message_id:
-        raise HTTPException(status_code=400, detail="message_id is required")
+        raise HTTPException(status_code=400, detail="message_id parameter is required and cannot be empty")
     
     if not chat_list_id:
-        raise HTTPException(status_code=400, detail="chat_list_id is required")
+        raise HTTPException(status_code=400, detail="chat_list_id parameter is required and cannot be empty")

Also applies to: 121-122

Backend/app/services/chat_services.py (2)

16-19: Consider distributed connection tracking for scalability.

The in-memory active_connections dictionary won't scale across multiple server instances. Each server would only track its own connections, causing issues with user presence and message delivery in a distributed deployment.

Consider using Redis or another distributed store to track active connections across all servers. This aligns with the PR objective of building a scalable video calling and chat system.


288-296: Simplify complex nested ternary for better readability.

The nested ternary operator is difficult to understand. Consider refactoring for clarity:

-        receiver_id = (
-            (
-                messages[0].receiver_id
-                if messages[0].sender_id == user_id
-                else messages[0].sender_id
-            )
-            if len(messages)
-            else None
-        )
+        receiver_id = None
+        if messages:
+            first_message = messages[0]
+            receiver_id = first_message.receiver_id if first_message.sender_id == user_id else first_message.sender_id
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f19677 and ca0ec78.

⛔ Files ignored due to path filters (1)
  • Frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (36)
  • Backend/app/db/db.py (2 hunks)
  • Backend/app/db/seed.py (1 hunks)
  • Backend/app/main.py (2 hunks)
  • Backend/app/models/chat.py (1 hunks)
  • Backend/app/models/models.py (8 hunks)
  • Backend/app/routes/chat.py (1 hunks)
  • Backend/app/services/chat_pubsub.py (1 hunks)
  • Backend/app/services/chat_services.py (1 hunks)
  • Backend/app/services/redis_client.py (1 hunks)
  • Backend/docker-compose.yml (1 hunks)
  • Frontend/.gitignore (1 hunks)
  • Frontend/package.json (3 hunks)
  • Frontend/src/App.tsx (1 hunks)
  • Frontend/src/components/chat/chat-item.tsx (1 hunks)
  • Frontend/src/components/chat/chat-list.tsx (1 hunks)
  • Frontend/src/components/chat/chat-search.tsx (1 hunks)
  • Frontend/src/components/chat/chat.tsx (1 hunks)
  • Frontend/src/components/chat/create-new-chat.tsx (1 hunks)
  • Frontend/src/components/chat/message-input.tsx (1 hunks)
  • Frontend/src/components/chat/message-item.tsx (1 hunks)
  • Frontend/src/components/chat/messages-list.tsx (1 hunks)
  • Frontend/src/components/chat/messages-view.tsx (1 hunks)
  • Frontend/src/components/chat/selected-user-card.tsx (1 hunks)
  • Frontend/src/components/ui/dialog.tsx (1 hunks)
  • Frontend/src/components/video-calling/call-starter.tsx (1 hunks)
  • Frontend/src/components/video-calling/video-call-ui.tsx (1 hunks)
  • Frontend/src/lib/useChat.tsx (1 hunks)
  • Frontend/src/lib/useVideocall.tsx (1 hunks)
  • Frontend/src/lib/utils.ts (1 hunks)
  • Frontend/src/main.tsx (1 hunks)
  • Frontend/src/pages/Brand/Dashboard.tsx (2 hunks)
  • Frontend/src/pages/Messages.tsx (3 hunks)
  • Frontend/src/redux/chatSlice.ts (1 hunks)
  • Frontend/src/redux/store.ts (1 hunks)
  • Frontend/src/types/chat.ts (1 hunks)
  • README.md (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
README.md (1)
Learnt from: muntaxir4
PR: AOSSIE-Org/InPactAI#56
File: Backend/app/services/redis_client.py:1-4
Timestamp: 2025-05-07T21:28:06.358Z
Learning: Hardcoded Redis connection parameters in Backend/app/services/redis_client.py are intentional during development, with plans to implement environment variable configuration later during production preparation.
Backend/app/services/redis_client.py (1)
Learnt from: muntaxir4
PR: AOSSIE-Org/InPactAI#56
File: Backend/app/services/redis_client.py:1-4
Timestamp: 2025-05-07T21:28:06.358Z
Learning: Hardcoded Redis connection parameters in Backend/app/services/redis_client.py are intentional during development, with plans to implement environment variable configuration later during production preparation.
Backend/docker-compose.yml (1)
Learnt from: muntaxir4
PR: AOSSIE-Org/InPactAI#56
File: Backend/app/services/redis_client.py:1-4
Timestamp: 2025-05-07T21:28:06.358Z
Learning: Hardcoded Redis connection parameters in Backend/app/services/redis_client.py are intentional during development, with plans to implement environment variable configuration later during production preparation.
Frontend/src/main.tsx (1)
Learnt from: muntaxir4
PR: AOSSIE-Org/InPactAI#56
File: Frontend/src/main.tsx:0-0
Timestamp: 2025-05-07T21:28:03.631Z
Learning: StrictMode in React should be disabled when using WebSockets in the application as it can cause unwanted disconnections due to the double-mounting behavior in development mode.
🧬 Code Graph Analysis (18)
Frontend/src/App.tsx (1)
Frontend/src/pages/Messages.tsx (1)
  • MessagesPage (141-402)
Backend/app/main.py (1)
Backend/app/db/seed.py (1)
  • seed_db (6-54)
Frontend/src/components/chat/message-input.tsx (4)
Frontend/src/redux/store.ts (1)
  • RootState (11-11)
Frontend/src/lib/useChat.tsx (1)
  • useChat (263-269)
Frontend/src/components/ui/input.tsx (1)
  • Input (21-21)
Frontend/src/components/ui/button.tsx (1)
  • Button (54-54)
Frontend/src/pages/Messages.tsx (1)
Frontend/src/components/chat/chat.tsx (1)
  • Chat (8-42)
Frontend/src/components/chat/chat-list.tsx (5)
Frontend/src/redux/store.ts (1)
  • RootState (11-11)
Frontend/src/redux/chatSlice.ts (1)
  • Chat (24-29)
Frontend/src/lib/useChat.tsx (1)
  • useChat (263-269)
Frontend/src/components/chat/create-new-chat.tsx (1)
  • CreateNewChat (19-100)
Frontend/src/components/chat/chat-item.tsx (1)
  • ChatItem (16-72)
Frontend/src/components/chat/selected-user-card.tsx (4)
Frontend/src/redux/store.ts (1)
  • RootState (11-11)
Frontend/src/lib/utils.ts (1)
  • API_URL (8-8)
Frontend/src/components/ui/avatar.tsx (3)
  • Avatar (50-50)
  • AvatarImage (50-50)
  • AvatarFallback (50-50)
Frontend/src/components/ui/button.tsx (1)
  • Button (54-54)
Backend/app/db/seed.py (1)
Backend/app/models/models.py (1)
  • User (24-56)
Frontend/src/components/chat/chat-item.tsx (6)
Frontend/src/components/chat/chat.tsx (1)
  • Chat (8-42)
Frontend/src/redux/chatSlice.ts (1)
  • Chat (24-29)
Frontend/src/redux/store.ts (1)
  • RootState (11-11)
Frontend/src/lib/useChat.tsx (1)
  • useChat (263-269)
Frontend/src/lib/utils.ts (1)
  • cn (4-6)
Frontend/src/components/ui/avatar.tsx (3)
  • Avatar (50-50)
  • AvatarImage (50-50)
  • AvatarFallback (50-50)
Frontend/src/components/chat/message-item.tsx (1)
Frontend/src/redux/chatSlice.ts (1)
  • Message (5-12)
Backend/app/models/chat.py (1)
Backend/app/models/models.py (1)
  • generate_uuid (19-20)
Frontend/src/components/video-calling/call-starter.tsx (4)
Frontend/src/lib/useChat.tsx (1)
  • useChat (263-269)
Frontend/src/redux/store.ts (1)
  • RootState (11-11)
Frontend/src/components/ui/dialog.tsx (3)
  • Dialog (123-123)
  • DialogTrigger (132-132)
  • DialogContent (125-125)
Frontend/src/components/ui/button.tsx (1)
  • Button (54-54)
Frontend/src/components/chat/messages-view.tsx (5)
Frontend/src/redux/store.ts (1)
  • RootState (11-11)
Frontend/src/lib/useChat.tsx (1)
  • useChat (263-269)
Frontend/src/components/chat/selected-user-card.tsx (1)
  • SelectedUserCard (27-99)
Frontend/src/components/chat/messages-list.tsx (1)
  • MessagesList (9-104)
Frontend/src/components/chat/message-input.tsx (1)
  • MessageInput (9-56)
Frontend/src/lib/useChat.tsx (3)
Frontend/src/lib/useVideocall.tsx (1)
  • useVideocall (7-171)
Frontend/src/lib/utils.ts (1)
  • API_URL (8-8)
Frontend/src/redux/chatSlice.ts (1)
  • Message (5-12)
Frontend/src/components/ui/dialog.tsx (1)
Frontend/src/lib/utils.ts (1)
  • cn (4-6)
Frontend/src/components/video-calling/video-call-ui.tsx (1)
Frontend/src/lib/useChat.tsx (1)
  • useChat (263-269)
Frontend/src/redux/chatSlice.ts (2)
Frontend/src/components/chat/chat.tsx (1)
  • Chat (8-42)
Frontend/src/types/chat.ts (1)
  • NewMessageResponse (6-16)
Frontend/src/components/chat/messages-list.tsx (4)
Frontend/src/redux/chatSlice.ts (1)
  • Message (5-12)
Frontend/src/redux/store.ts (1)
  • RootState (11-11)
Frontend/src/lib/useChat.tsx (1)
  • useChat (263-269)
Frontend/src/components/chat/message-item.tsx (1)
  • MessageItem (6-55)
Backend/app/services/chat_services.py (3)
Backend/app/models/models.py (1)
  • User (24-56)
Backend/app/models/chat.py (3)
  • ChatList (19-32)
  • ChatMessage (35-54)
  • MessageStatus (13-16)
Backend/app/routes/chat.py (7)
  • get_chat_history (89-95)
  • mark_message_as_read (99-111)
  • mark_chat_as_read (115-124)
  • get_user_status (80-85)
  • get_user_chat_list (71-76)
  • get_user_name (66-67)
  • create_new_chat_message (128-139)
🪛 LanguageTool
README.md

[uncategorized] ~166-~166: Possible missing preposition found.
Context: ...onsole](https://console.groq.com/) - Create an API key and paste it into the .env...

(AI_HYDRA_LEO_MISSING_TO)

🪛 Pylint (3.3.7)
Backend/app/db/seed.py

[error] 2-2: No name 'db' in module 'db'

(E0611)


[refactor] 35-50: Unnecessary "else" after "continue", remove the "else" and de-indent the code inside it

(R1724)

Backend/app/models/chat.py

[refactor] 19-19: Too few public methods (0/2)

(R0903)


[refactor] 35-35: Too few public methods (0/2)

(R0903)

Backend/app/services/chat_services.py

[refactor] 62-62: Too many arguments (6/5)

(R0913)


[refactor] 62-62: Too many positional arguments (6/5)

(R0917)


[refactor] 224-224: Too many arguments (6/5)

(R0913)


[refactor] 224-224: Too many positional arguments (6/5)

(R0917)


[refactor] 391-391: Too many arguments (6/5)

(R0913)


[refactor] 391-391: Too many positional arguments (6/5)

(R0917)


[refactor] 427-427: Too many arguments (6/5)

(R0913)


[refactor] 427-427: Too many positional arguments (6/5)

(R0917)

🪛 Flake8 (7.2.0)
Backend/app/db/seed.py

[error] 1-1: 'datetime.datetime' imported but unused

(F401)


[error] 1-1: 'datetime.timezone' imported but unused

(F401)

🪛 Ruff (0.11.9)
Backend/app/db/seed.py

1-1: datetime.datetime imported but unused

Remove unused import

(F401)


1-1: datetime.timezone imported but unused

Remove unused import

(F401)

Backend/app/routes/chat.py

24-24: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


25-25: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


66-66: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


74-74: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


82-82: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


83-83: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


93-93: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


103-103: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


104-104: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


118-118: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


119-119: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


132-132: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


133-133: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (24)
Backend/app/db/db.py (2)

22-24: LGTM: Improved code formatting

The multi-line formatting of the create_async_engine call enhances readability while maintaining the same functionality.


38-40: LGTM: Proper async session management

The get_db function correctly implements the dependency injection pattern for FastAPI with proper async session handling and automatic cleanup.

Frontend/.gitignore (1)

1-1: LGTM: Essential security practice

Adding .env* to gitignore prevents accidental commits of environment files containing sensitive configuration data like API keys.

Backend/app/services/redis_client.py (1)

6-7: LGTM: Simple dependency injection pattern

The get_redis function correctly provides the Redis client for dependency injection.

Frontend/src/lib/utils.ts (3)

1-2: LGTM: Improved syntax consistency

Adding semicolons to import statements improves code consistency and follows JavaScript/TypeScript best practices.


5-5: LGTM: Consistent semicolon usage

Adding the semicolon to the return statement maintains syntax consistency throughout the file.


8-8: LGTM: Proper environment variable configuration

The API_URL constant correctly uses Vite's environment variable system with a sensible fallback, providing flexibility for different deployment environments.

README.md (2)

120-124: LGTM: Essential Redis setup documentation

The addition of Redis server setup instructions is crucial since the backend now depends on Redis for chat functionality. The placement before backend setup is logical.


126-126: LGTM: Proper step numbering updates

The step numbering has been correctly incremented throughout the documentation to accommodate the new Redis setup step.

Also applies to: 132-133, 163-163, 168-168

Frontend/package.json (1)

14-14: Dependencies look good for chat feature support.

The new dependencies are well-chosen for the chat and video calling implementation:

  • @radix-ui/react-dialog for modal UI components
  • @reduxjs/toolkit and react-redux for state management
  • axios for HTTP client functionality

The versions appear current and appropriate.

Also applies to: 25-25, 28-28, 38-38

Frontend/src/main.tsx (1)

4-4: Redux integration implemented correctly.

The Redux Provider wrapper is properly configured with the imported store, enabling global state management for the chat features.

Also applies to: 6-6, 10-12

Frontend/src/pages/Brand/Dashboard.tsx (2)

1-1: Good component import for the new chat functionality.

The Chat component import aligns with the new chat system implementation.


273-278: Excellent refactoring to use the new Chat component.

Replacing the complex inline messaging UI with the dedicated Chat component improves maintainability and follows good separation of concerns principles. The commented className indicates thoughtful removal of the now-unnecessary grid layout.

Frontend/src/pages/Messages.tsx (2)

23-23: LGTM! Clean import of the new Chat component.

The import statement is correctly structured and follows the established pattern.


399-399: LGTM! Proper integration of the new Chat component.

The Chat component is cleanly integrated into the page structure.

Frontend/src/components/chat/chat.tsx (1)

34-36: Verify responsive design for the grid layout.

The hard-coded grid-cols-12 layout may not be responsive on smaller screens.

Please verify that the ChatList and MessagesView components handle responsive design appropriately, or consider making the grid layout responsive:

-          <div className="grid grid-cols-12 gap-6">
+          <div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
Frontend/src/redux/store.ts (1)

1-13: LGTM! Clean and properly configured Redux store.

The store setup follows Redux Toolkit best practices with:

  • Proper TypeScript typing for RootState and AppDispatch
  • Clean configuration with configureStore
  • Appropriate exports for type inference
Backend/app/services/chat_pubsub.py (1)

10-16: Verify proper cleanup of Redis connections.

Ensure that the Redis pubsub connection is always properly closed, even if exceptions occur during the unsubscribe process.

Consider making the cleanup more robust:

    finally:
-        await pubsub.unsubscribe(f"to_user:{user_id}")
-        await pubsub.close()
+        try:
+            await pubsub.unsubscribe(f"to_user:{user_id}")
+        except Exception as e:
+            logger.warning(f"Failed to unsubscribe from channel: {e}")
+        try:
+            await pubsub.close()
+        except Exception as e:
+            logger.warning(f"Failed to close pubsub connection: {e}")
Backend/app/main.py (1)

2-2: Well-structured integration of chat functionality.

The changes properly integrate the new chat features:

  • CORS middleware configured for frontend communication
  • Chat models and routes properly included
  • Database seeding called during startup
  • Both existing and chat tables created

The implementation follows FastAPI best practices for application lifecycle management.

Also applies to: 7-7, 23-23, 34-34, 43-53

Frontend/src/components/chat/chat-list.tsx (1)

13-68: Well-implemented chat list component.

The component demonstrates good React practices:

  • Proper state management with Redux
  • Loading states and conditional rendering
  • Clean separation of concerns
  • Effective use of hooks for data fetching and sorting

The sorting logic and UI structure are well-designed for a chat interface.

Frontend/src/components/chat/selected-user-card.tsx (1)

55-61: Good interval cleanup implementation.

The useEffect properly cleans up the interval to prevent memory leaks, which is a good practice for periodic data fetching.

Frontend/src/components/video-calling/call-starter.tsx (1)

24-42: Well-structured call starter component.

The component properly integrates the dialog UI with video call functionality and follows good React patterns for state management and event handling.

Backend/app/models/models.py (1)

34-41: Well-implemented timezone-aware timestamps and relationship improvements

The changes properly implement timezone-aware datetime fields across all models and clarify the payment relationships by splitting them into payments and brand_payments. The addition of online status tracking fields (is_online, last_seen) supports the new chat feature effectively.

Also applies to: 47-56, 71-73, 90-92, 109-111, 126-128, 143-145, 158-165

Backend/app/routes/chat.py (1)

73-73: I’ll check the project’s declared Python requirement to determine if using the str | None syntax is safe.

<Route path="/reset-password" element={<ResetPasswordPage />} />
<Route path="/brand/dashboard" element={<Dashboard />} />
<Route path="/basicDetails/:user" element={<BasicDetails />} />
<Route path="/creator/messages" element={<MessagesPage />} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Security concern: Public access to messaging functionality.

The new /creator/messages route provides public access to the MessagesPage component without authentication. This could expose sensitive messaging functionality to unauthorized users.

Consider:

  1. Is this intentional for a specific use case (e.g., public creator profiles)?
  2. Should this route have authentication protection like the existing /dashboard/messages?
  3. Will there be role-based access control to ensure only creators can access this route?

🏁 Script executed:

#!/bin/bash
# Verify if there's role-based access control in the MessagesPage component
ast-grep --pattern 'function MessagesPage() {
  $$$
}'

Length of output: 19408


🏁 Script executed:

#!/bin/bash
# Show the /creator/messages route and its surrounding context in App.tsx to verify authentication wrappers
rg -n -C5 'path="/creator/messages"' Frontend/src/App.tsx

Length of output: 622


Security concern: Unauthenticated access to /creator/messages.

The new route at Frontend/src/App.tsx:32 is declared alongside public routes (/signup, /forgot-password, etc.) and renders MessagesPage without any authentication or role check. This effectively exposes your messaging UI to unauthenticated users.

Please clarify or address the following:

  • Is it intentional to allow public (unauthenticated) access to creators’ messages?
  • Should this route be wrapped in your auth guard (e.g. <RequireAuth>) like /dashboard/messages?
  • If only creators should access this, implement role-based protection to block unauthorized users.
🤖 Prompt for AI Agents
In Frontend/src/App.tsx at line 32, the route for "/creator/messages" renders
MessagesPage without any authentication or role checks, exposing it to
unauthenticated users. To fix this, wrap the <Route> element with your
authentication guard component (e.g., <RequireAuth>) to enforce login, and add
role-based authorization logic to ensure only users with the creator role can
access this route. This will prevent unauthorized or unauthenticated access to
the messaging UI.

@@ -0,0 +1,13 @@
services:
redis:
image: redis:latest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using a specific Redis version instead of 'latest'.

Using redis:latest can lead to unexpected behavior when the image is updated. Consider pinning to a specific version for consistency.

-    image: redis:latest
+    image: redis:7-alpine
🤖 Prompt for AI Agents
In Backend/docker-compose.yml at line 3, replace the image tag 'redis:latest'
with a specific Redis version tag, such as 'redis:7.0' or another stable
version. This ensures consistent behavior by avoiding automatic updates to the
latest image.

Comment on lines +24 to +26
onClick={() => {
setUserId(inputUserId);
}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation and prevent empty user IDs.

The current implementation allows setting an empty or whitespace-only user ID, which could cause issues downstream.

Apply this improvement:

          onClick={() => {
-            setUserId(inputUserId);
+            if (inputUserId?.trim()) {
+              setUserId(inputUserId.trim());
+            }
          }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onClick={() => {
setUserId(inputUserId);
}}
onClick={() => {
if (inputUserId?.trim()) {
setUserId(inputUserId.trim());
}
}}
🤖 Prompt for AI Agents
In Frontend/src/components/chat/chat.tsx around lines 24 to 26, the onClick
handler sets the user ID without validation, allowing empty or whitespace-only
values. Add a check before calling setUserId to ensure inputUserId is not empty
or only whitespace. If the input is invalid, prevent setting the user ID to
avoid downstream issues.

try:
async for message in pubsub.listen():
if message["type"] == "message":
await websocket.send_json(json.loads(message["data"]))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for JSON parsing and WebSocket operations.

The current implementation could crash if malformed JSON is received or if the WebSocket connection fails.

Apply this improvement for robust error handling:

            if message["type"] == "message":
-                await websocket.send_json(json.loads(message["data"]))
+                try:
+                    data = json.loads(message["data"])
+                    await websocket.send_json(data)
+                except json.JSONDecodeError as e:
+                    print(f"Failed to parse JSON message: {e}")
+                except Exception as e:
+                    print(f"Failed to send WebSocket message: {e}")
+                    break  # Exit loop if WebSocket is broken
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await websocket.send_json(json.loads(message["data"]))
if message["type"] == "message":
try:
data = json.loads(message["data"])
await websocket.send_json(data)
except json.JSONDecodeError as e:
print(f"Failed to parse JSON message: {e}")
except Exception as e:
print(f"Failed to send WebSocket message: {e}")
break # Exit loop if WebSocket is broken
🤖 Prompt for AI Agents
In Backend/app/services/chat_pubsub.py at line 13, add try-except blocks around
the JSON parsing and websocket send operation to catch and handle exceptions
from json.loads and websocket.send_json. Log or handle errors gracefully to
prevent crashes when malformed JSON is received or the WebSocket connection
fails.

Comment on lines +6 to +16
async def listen_to_channel(user_id: str, websocket: WebSocket, redis_client: Redis):
pubsub = redis_client.pubsub()
await pubsub.subscribe(f"to_user:{user_id}")

try:
async for message in pubsub.listen():
if message["type"] == "message":
await websocket.send_json(json.loads(message["data"]))
finally:
await pubsub.unsubscribe(f"to_user:{user_id}")
await pubsub.close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add logging and connection monitoring for better observability.

The function lacks logging and monitoring capabilities, making it difficult to debug issues in production.

Consider adding logging and connection health monitoring:

+import logging
+
+logger = logging.getLogger(__name__)

async def listen_to_channel(user_id: str, websocket: WebSocket, redis_client: Redis):
+    logger.info(f"Starting Redis channel listener for user {user_id}")
    pubsub = redis_client.pubsub()
    await pubsub.subscribe(f"to_user:{user_id}")

    try:
        async for message in pubsub.listen():
            if message["type"] == "message":
+                logger.debug(f"Received message for user {user_id}: {message}")
                # ... error handling code ...
    except Exception as e:
+        logger.error(f"Error in channel listener for user {user_id}: {e}")
+        raise
    finally:
+        logger.info(f"Closing Redis channel listener for user {user_id}")
        await pubsub.unsubscribe(f"to_user:{user_id}")
        await pubsub.close()

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In Backend/app/services/chat_pubsub.py around lines 6 to 16, the
listen_to_channel function lacks logging and connection health monitoring, which
reduces observability. Add logging statements to record subscription events,
received messages, and any exceptions. Also, implement connection health checks
or heartbeat logs to monitor the websocket and Redis pubsub connection status
during the async loop. This will help track the function's behavior and diagnose
issues in production.

Comment on lines +59 to +77
<div className="flex flex-col mb-4">
<label className="text-center mb-2 font-bold">{localVideoLabel}</label>
<video
ref={localVideoRef}
autoPlay
muted
playsInline
className="w-80 h-60 border border-gray-300 bg-black"
style={{
position: "absolute",
bottom: "1rem",
right: "1rem",
width: "20%",
height: "20%",
zIndex: 10,
}}
/>
</div>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix conflicting styles and label positioning for local video.

The local video has conflicting dimension styles and the label is detached from the video due to absolute positioning.

Remove conflicting styles and fix the structure:

       <div className="flex flex-col mb-4">
-        <label className="text-center mb-2 font-bold">{localVideoLabel}</label>
         <video
           ref={localVideoRef}
           autoPlay
           muted
           playsInline
-          className="w-80 h-60 border border-gray-300 bg-black"
+          className="border border-gray-300 bg-black"
           style={{
             position: "absolute",
             bottom: "1rem",
             right: "1rem",
             width: "20%",
             height: "20%",
             zIndex: 10,
           }}
         />
       </div>

Consider adding the label as an overlay on the video if needed.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="flex flex-col mb-4">
<label className="text-center mb-2 font-bold">{localVideoLabel}</label>
<video
ref={localVideoRef}
autoPlay
muted
playsInline
className="w-80 h-60 border border-gray-300 bg-black"
style={{
position: "absolute",
bottom: "1rem",
right: "1rem",
width: "20%",
height: "20%",
zIndex: 10,
}}
/>
</div>
<div className="flex flex-col mb-4">
<video
ref={localVideoRef}
autoPlay
muted
playsInline
className="border border-gray-300 bg-black"
style={{
position: "absolute",
bottom: "1rem",
right: "1rem",
width: "20%",
height: "20%",
zIndex: 10,
}}
/>
</div>
🤖 Prompt for AI Agents
In Frontend/src/components/video-calling/video-call-ui.tsx between lines 59 and
77, the local video element has conflicting width and height styles set both via
className and inline styles, and the absolute positioning causes the label to be
detached from the video. Remove the inline width and height styles to avoid
conflicts, and eliminate the absolute positioning to keep the label and video
together. Optionally, wrap the video and label in a relative container and
position the label as an overlay inside that container if overlay labeling is
desired.

{...props}
>
{children}
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix invalid Tailwind CSS class rounded-xs

The class rounded-xs is not a standard Tailwind CSS utility. Use rounded-sm for small border radius or rounded for default radius.

-        <DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
+        <DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
🤖 Prompt for AI Agents
In Frontend/src/components/ui/dialog.tsx at line 64, replace the invalid
Tailwind CSS class `rounded-xs` with a valid class such as `rounded-sm` for a
small border radius or `rounded` for the default border radius to ensure proper
styling.

Comment on lines +50 to +56
setTimeout(() => {
if (messagesContainerRef.current) {
messagesContainerRef.current.scrollTop =
messagesContainerRef.current.scrollHeight;
}
}, 1000);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace arbitrary timeout with layout effect

Using a 1000ms timeout to scroll after marking messages as seen is unreliable. Consider using useLayoutEffect or a callback after the state update completes.

🤖 Prompt for AI Agents
In Frontend/src/components/chat/messages-view.tsx around lines 50 to 56, replace
the setTimeout with a useLayoutEffect hook or a callback that triggers scrolling
immediately after the messages state updates. This ensures the scroll happens
right after the DOM updates instead of waiting an arbitrary 1000ms, making the
scroll behavior more reliable and responsive.

Comment on lines +79 to +88
useEffect(() => {
if (
selectedChatId &&
chatMessageIds.length === 0 &&
!initialLoadPerformedRef.current
) {
initialLoadPerformedRef.current = true;
loadMessages(0);
}
}, [selectedChatId, chatMessageIds.length]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add missing dependencies to useEffect

The effect uses loadMessages function but doesn't include it in the dependency array. This could lead to stale closures.

Consider wrapping loadMessages with useCallback and including it in the dependency array, or move the function definition inside the effect.

🤖 Prompt for AI Agents
In Frontend/src/components/chat/messages-view.tsx around lines 79 to 88, the
useEffect hook uses the loadMessages function but does not include it in the
dependency array, risking stale closures. To fix this, either wrap loadMessages
in useCallback to memoize it and then add it to the dependency array, or move
the loadMessages function definition inside the useEffect hook so it does not
need to be a dependency.

Comment on lines +69 to +74
setTimeout(() => {
if (messagesContainerRef.current) {
messagesContainerRef.current.scrollTop =
messagesContainerRef.current.scrollHeight;
}
}, 10);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unreliable timeout for initial scroll

The 10ms timeout for scrolling is a code smell that indicates a race condition. Use useLayoutEffect to ensure the DOM is updated before scrolling.

-      setTimeout(() => {
-        if (messagesContainerRef.current) {
-          messagesContainerRef.current.scrollTop =
-            messagesContainerRef.current.scrollHeight;
-        }
-      }, 10);
+      // Move this logic to a useLayoutEffect that runs after DOM updates
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setTimeout(() => {
if (messagesContainerRef.current) {
messagesContainerRef.current.scrollTop =
messagesContainerRef.current.scrollHeight;
}
}, 10);
// Move this logic to a useLayoutEffect that runs after DOM updates
🤖 Prompt for AI Agents
In Frontend/src/components/chat/messages-view.tsx around lines 69 to 74, replace
the setTimeout-based scrolling logic with a useLayoutEffect hook to perform the
scroll after the DOM updates. This ensures the scroll happens reliably without
relying on an arbitrary timeout, preventing race conditions. Move the scroll
code inside a useLayoutEffect that depends on the messages or relevant state to
trigger scrolling after rendering.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review continued from previous batch...

Comment on lines +91 to +99
useEffect(() => {
if (messages.length > 0) {
const oldestMessageTime = new Date(messages[0].createdAt).getTime();
// Only update if we have a new oldest message
if (oldestMessageTime < lastFetchedTime) {
setLastFetchedTime(oldestMessageTime);
}
}
}, [messages, lastFetchedTime]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add safety check for empty messages array

Accessing messages[0] without checking if the array is empty could cause a runtime error.

   useEffect(() => {
-    if (messages.length > 0) {
+    if (messages.length > 0 && messages[0]) {
       const oldestMessageTime = new Date(messages[0].createdAt).getTime();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
if (messages.length > 0) {
const oldestMessageTime = new Date(messages[0].createdAt).getTime();
// Only update if we have a new oldest message
if (oldestMessageTime < lastFetchedTime) {
setLastFetchedTime(oldestMessageTime);
}
}
}, [messages, lastFetchedTime]);
useEffect(() => {
if (messages.length > 0 && messages[0]) {
const oldestMessageTime = new Date(messages[0].createdAt).getTime();
// Only update if we have a new oldest message
if (oldestMessageTime < lastFetchedTime) {
setLastFetchedTime(oldestMessageTime);
}
}
}, [messages, lastFetchedTime]);
🤖 Prompt for AI Agents
In Frontend/src/components/chat/messages-view.tsx around lines 91 to 99, add a
safety check to ensure the messages array is not empty before accessing
messages[0]. Modify the useEffect to first verify messages.length > 0 before
attempting to read messages[0].createdAt to prevent runtime errors from
accessing an element in an empty array.

Comment on lines +145 to +156
removeChat: (state, action: PayloadAction<string>) => {
const chatListId = action.payload;

// Remove the chat
delete state.chats[chatListId];

// Remove all messages associated with the chat
const messageIds = state.chats[chatListId]?.messageIds || [];
messageIds.forEach((messageId) => {
delete state.messages[messageId];
});
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix critical logic error in removeChat reducer

The reducer deletes the chat on line 149 but then tries to access its messageIds on line 152, which will always be undefined.

   removeChat: (state, action: PayloadAction<string>) => {
     const chatListId = action.payload;

+    // Get message IDs before deleting the chat
+    const messageIds = state.chats[chatListId]?.messageIds || [];
+
     // Remove the chat
     delete state.chats[chatListId];

     // Remove all messages associated with the chat
-    const messageIds = state.chats[chatListId]?.messageIds || [];
     messageIds.forEach((messageId) => {
       delete state.messages[messageId];
     });
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
removeChat: (state, action: PayloadAction<string>) => {
const chatListId = action.payload;
// Remove the chat
delete state.chats[chatListId];
// Remove all messages associated with the chat
const messageIds = state.chats[chatListId]?.messageIds || [];
messageIds.forEach((messageId) => {
delete state.messages[messageId];
});
},
removeChat: (state, action: PayloadAction<string>) => {
const chatListId = action.payload;
// Get message IDs before deleting the chat
const messageIds = state.chats[chatListId]?.messageIds || [];
// Remove the chat
delete state.chats[chatListId];
// Remove all messages associated with the chat
messageIds.forEach((messageId) => {
delete state.messages[messageId];
});
},
🤖 Prompt for AI Agents
In Frontend/src/redux/chatSlice.ts between lines 145 and 156, the removeChat
reducer deletes the chat from state.chats before trying to access its
messageIds, causing messageIds to be undefined. To fix this, first retrieve and
store the messageIds from the chat before deleting the chat, then proceed to
delete the chat and its associated messages using the stored messageIds.

Comment on lines +58 to +62
except Exception as e:
listener_task.cancel()
await chat_service.disconnect(user_id, redis, db)
# Optionally log the error
print(f"Error in websocket for user {user_id}: {e}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace print() with proper logging

Using print() for error logging in production code is not recommended. Use Python's logging module instead.

+import logging
+
+logger = logging.getLogger(__name__)
+
     except Exception as e:
         listener_task.cancel()
         await chat_service.disconnect(user_id, redis, db)
-        # Optionally log the error
-        print(f"Error in websocket for user {user_id}: {e}")
+        logger.error(f"Error in websocket for user {user_id}: {e}", exc_info=True)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except Exception as e:
listener_task.cancel()
await chat_service.disconnect(user_id, redis, db)
# Optionally log the error
print(f"Error in websocket for user {user_id}: {e}")
import logging
logger = logging.getLogger(__name__)
except Exception as e:
listener_task.cancel()
await chat_service.disconnect(user_id, redis, db)
logger.error(f"Error in websocket for user {user_id}: {e}", exc_info=True)
🤖 Prompt for AI Agents
In Backend/app/routes/chat.py around lines 58 to 62, replace the print statement
used for error logging with the Python logging module. Import the logging module
if not already done, create or use an existing logger, and replace the print
call with logger.error including the error message and user_id for proper error
tracking in production.

Comment on lines +282 to +285
for message in messages:
if message.sender_id == user_id:
message.status = MessageStatus.SEEN

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect logic for marking messages as read.

The current logic marks messages sent by the user as SEEN, but it should mark messages received by the user as SEEN.

-        for message in messages:
-            if message.sender_id == user_id:
-                message.status = MessageStatus.SEEN
+        for message in messages:
+            if message.receiver_id == user_id:
+                message.status = MessageStatus.SEEN
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for message in messages:
if message.sender_id == user_id:
message.status = MessageStatus.SEEN
for message in messages:
- if message.sender_id == user_id:
+ if message.receiver_id == user_id:
message.status = MessageStatus.SEEN
🤖 Prompt for AI Agents
In Backend/app/services/chat_services.py around lines 282 to 285, the logic
incorrectly marks messages sent by the user as SEEN. Update the condition to
mark messages where the sender_id is not the user_id (i.e., messages received by
the user) as SEEN instead.

"createdAt": new_message.created_at.isoformat(),
"isSent": True,
"status": "sent",
"senderId": receiver_id,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect senderId in NEW_MESSAGE_SENT event.

The senderId should be the actual sender's ID, not the receiver's ID. This bug would cause messages to be incorrectly attributed in the chat UI.

-                            "senderId": receiver_id,
+                            "senderId": sender_id,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"senderId": receiver_id,
"senderId": sender_id,
🤖 Prompt for AI Agents
In Backend/app/services/chat_services.py at line 168, the senderId is
incorrectly set to the receiver_id. Change the senderId to use the actual
sender's ID variable instead of receiver_id to ensure messages are correctly
attributed in the chat UI.

Comment on lines +5 to +6
from models.models import User
from models.chat import ChatList, ChatMessage, MessageStatus
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect import paths.

The import paths should be relative or absolute based on the project structure. Since this file is at Backend/app/services/chat_services.py, the imports should be:

-from models.models import User
-from models.chat import ChatList, ChatMessage, MessageStatus
+from ..models.models import User
+from ..models.chat import ChatList, ChatMessage, MessageStatus
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from models.models import User
from models.chat import ChatList, ChatMessage, MessageStatus
from ..models.models import User
from ..models.chat import ChatList, ChatMessage, MessageStatus
🤖 Prompt for AI Agents
In Backend/app/services/chat_services.py around lines 5 to 6, the import paths
for User, ChatList, ChatMessage, and MessageStatus are incorrect. Adjust the
import statements to use relative imports based on the file location, for
example, use from ..models.models import User and from ..models.chat import
ChatList, ChatMessage, MessageStatus, or use the correct absolute import paths
according to the project structure.

Comment on lines +419 to +423
if chat_list:
return {
"chatListId": chat_list.scalar_one().id,
"isChatListExists": True,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect chat list existence check.

The code checks the query result object instead of extracting the actual value. This would cause the condition to always be truthy.

         chat_list = await db.execute(
             select(ChatList).where(
                 ((ChatList.user1_id == user_id) & (ChatList.user2_id == receiver.id))
                 | ((ChatList.user1_id == receiver.id) & (ChatList.user2_id == user_id))
             )
         )
-        if chat_list:
+        chat_list = chat_list.scalar_one_or_none()
+        if chat_list:
             return {
-                "chatListId": chat_list.scalar_one().id,
+                "chatListId": chat_list.id,
                 "isChatListExists": True,
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if chat_list:
return {
"chatListId": chat_list.scalar_one().id,
"isChatListExists": True,
}
chat_list = await db.execute(
select(ChatList).where(
((ChatList.user1_id == user_id) & (ChatList.user2_id == receiver.id))
| ((ChatList.user1_id == receiver.id) & (ChatList.user2_id == user_id))
)
)
chat_list = chat_list.scalar_one_or_none()
if chat_list:
return {
"chatListId": chat_list.id,
"isChatListExists": True,
}
🤖 Prompt for AI Agents
In Backend/app/services/chat_services.py around lines 419 to 423, the condition
checks the query result object directly instead of the extracted value, causing
it to always evaluate as true. Modify the code to first extract the scalar value
from chat_list using scalar_one() or an equivalent method, then check if that
extracted value exists before returning the dictionary. This ensures the
existence check is performed on the actual data, not the query object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants